﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using context;
using entities;

namespace DataAccessLibrary.DAL
{
    public class CheckoutDAO
    {
        public bool CheckOut(List<int> checkinId, int employeeId)
        {
            using (var ctx = new BlueMDataContext())
            {
                List<CheckIn> checkins =
                    checkinId.Select(i => ctx.CheckIns.First(p => p.CheckInID == i)).ToList();

                if (checkins.GroupBy(p => p.BookingID).Count() != 1)
                    throw new Exception("Invalid booking");
                return CheckOutDo(checkins, employeeId);
            }
        }


        private bool CheckOutDo(IEnumerable<CheckIn> checkins, int employeeId)
        {
            using (var ctx = new BlueMDataContext())
            {
                foreach (CheckIn checkin in checkins)
                {
                    if (checkin == null)
                        throw new Exception("Invalid checkin list!");

                    if (checkin.Payment == null)
                        throw new Exception("Invalid checkin payment");

                    checkin.CheckOutEmployee = employeeId;
                }

                ctx.SubmitChanges();
            }

            return true;
        }


        public List<vBill> SelectBill(List<int> checkinId, int employeeId = 0)
        {
            using (var ctx = new BlueMDataContext())
            {
                List<CheckIn> checkIns = checkinId.Select(i => ctx.CheckIns.First(p => p.CheckInID == i)).ToList();

                if (checkIns.GroupBy(p => p.BookingID).Count() != 1)
                    throw new Exception("Invalid booking");
                decimal totalpayment = PaymentCheckin(checkIns);
                if (totalpayment <= 0)
                    throw new Exception("Can not create payment");

                var listBills = new List<vBill>();
                
                if (employeeId>0)
                {
                    var booking = checkIns.First().Booking;
                    foreach (var checkIn in checkIns)
                    {
                        checkIn.CheckOutEmployee = employeeId;
                    }
                    if (booking.CheckIns.Count == checkinId.Count)
                    {
                        booking.TotalPayment = totalpayment;
                    }
                    ctx.SubmitChanges();
                    foreach (int i in checkinId)
                    {
                        int ch = i;
                        listBills.AddRange(ctx.vBills.Where(p => p.CheckInID == ch));
                    }
                }
                else
                {
                    foreach (int i in checkinId)
                    {
                        int ch = i;
                        listBills.AddRange(ctx.vBills.Where(p => p.CheckInID == ch));
                    }
                    foreach (var bill in listBills)
                    {
                        bill.TotalPayment = totalpayment;
                        foreach (var checkIn in checkIns)
                        {
                            if (bill.CheckInID == checkIn.CheckInID)
                            {
                                bill.Payment = checkIn.Payment;
                            }
                        }
                    }
                }
                return listBills;
            }
        }

       
        private decimal PaymentCheckin(IEnumerable<CheckIn> checkIns)
        {
            decimal result = 0;
            foreach (CheckIn checkin in checkIns)
            {
                if (checkin != null && (checkin.CheckOutEmployee == null && checkin.CheckInEmployee != null))
                {
                    TimeSpan occ = checkin.CheckOutDate - checkin.CheckInDate;
                    decimal roomPrice = checkin.Room.RoomType.RoomPrice;
                    decimal chkPayment = PaymentRoom(occ, roomPrice) + PaymentSupplys(checkin.Supplies);
                    checkin.Payment = chkPayment;
                    result += chkPayment;
                }
                else
                {
                    throw new Exception("Invalided Checkin!");
                }
            }
            if (result == 0)
                throw new Exception("Invalided Checkin!");
            return result;
        }

        private decimal PaymentRoom(TimeSpan occ, decimal roomPrice)
        {
            int day = occ.Days;
            int hour = occ.Hours;
            decimal occPayment = day * roomPrice;

            if (hour > 12)
                occPayment += roomPrice;
            else if (hour > 6)
                occPayment += (roomPrice * 60) / 100;
            else if (hour > 3)
                occPayment += (roomPrice * 40) / 100;
            else
                occPayment += (roomPrice * 20) / 100;

            return occPayment;
        }


        private decimal PaymentSupplys(IEnumerable<Supply> supplies)
        {
            var result = supplies.Sum(p => (p.SupplyNumber * p.SupplyDetail.SupplyPrice));
            return result;
        }
    }
}